123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- <template>
- <div class="py-8">
- <div class="container-custom">
- <div class="mb-4">
- <NuxtLink to="/faq" class="text-blue-600 hover:underline flex items-center">
- <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
- </svg>
- {{ $t('faq.title') }}
- </NuxtLink>
- </div>
-
- <ErrorBoundary :error="error">
- <div v-if="isLoading" class="flex justify-center py-12">
- <!-- 加载中 -->
- <div class="animate-spin h-8 w-8 border-4 border-blue-500 rounded-full border-t-transparent"></div>
- </div>
-
- <div v-else-if="faq" class="bg-white border border-gray-200 rounded-lg overflow-hidden">
- <div class="p-8">
- <div class="mb-2 flex items-center text-sm text-blue-600">
- <span class="px-3 py-1 bg-blue-100 rounded-full">{{ faq.category }}</span>
- </div>
-
- <h1 class="text-3xl font-bold mb-6">{{ faq.question }}</h1>
-
- <div class="prose max-w-none text-gray-700">
- <p>{{ faq.answer }}</p>
- </div>
-
- <div class="mt-12 pt-6 border-t border-gray-200">
- <h2 class="text-xl font-semibold mb-4">相关问题</h2>
- <ul class="space-y-3">
- <li v-for="relatedFaq in relatedFaqs" :key="relatedFaq.id">
- <NuxtLink
- :to="`/faq/${relatedFaq.id}`"
- class="text-blue-600 hover:text-blue-800 hover:underline"
- >
- {{ relatedFaq.question }}
- </NuxtLink>
- </li>
- </ul>
- </div>
-
- <div class="mt-12 pt-6 border-t border-gray-200">
- <h2 class="text-xl font-semibold mb-4">没有找到您需要的答案?</h2>
- <p class="text-gray-600 mb-4">
- 如果您有其他问题或需要更详细的信息,请随时联系我们的客服团队。
- </p>
- <NuxtLink to="/contact" class="btn btn-primary">
- 联系我们
- </NuxtLink>
- </div>
- </div>
- </div>
-
- <div v-else class="bg-yellow-50 border border-yellow-200 text-yellow-800 p-4 rounded-md">
- 未找到该问题,可能已被删除或移动。
- </div>
- </ErrorBoundary>
- </div>
- </div>
- </template>
-
- <script setup lang="ts">
- /**
- * FAQ详情页面
- * 展示单个FAQ详细内容和相关问题
- */
- import { ref, computed, onMounted } from 'vue';
- import { useErrorHandler } from '~/composables/useErrorHandler';
-
- // FAQ接口定义
- interface Faq {
- id: number;
- question: string;
- answer: string;
- category: string;
- }
-
- const route = useRoute();
- const { error, isLoading, wrapAsync } = useErrorHandler();
- const faq = ref<Faq | null>(null);
- const allFaqs = ref<Faq[]>([]);
-
- // 获取FAQ ID
- const faqId = computed(() => {
- const id = route.params.id;
- return typeof id === 'string' ? parseInt(id, 10) : -1;
- });
-
- // 相关问题
- const relatedFaqs = computed(() => {
- if (!faq.value) return [];
-
- // 查找同类别的其他问题,最多返回3个
- return allFaqs.value
- .filter(item => item.id !== faq.value?.id && item.category === faq.value?.category)
- .slice(0, 3);
- });
-
- /**
- * 加载FAQ详情数据
- */
- async function loadFaqDetail() {
- if (faqId.value <= 0) {
- error.value = new Error('无效的FAQ ID');
- return;
- }
-
- await wrapAsync(async () => {
- // 模拟API请求延迟
- await new Promise(resolve => setTimeout(resolve, 500));
-
- // 模拟数据,实际项目中应从API获取
- const mockFaqs = [
- {
- id: 1,
- question: '如何使用产品?',
- answer: '我们的产品设计简单直观,开箱即用。首先,打开包装并检查所有配件是否齐全。然后,按照说明书的步骤进行安装。如有任何问题,可以观看我们网站上的视频教程或联系客服。\n\n大多数产品只需简单的几个步骤即可完成安装和初始设置。我们还提供在线指南和视频教程,帮助您更好地理解产品功能和使用方法。如果您在使用过程中遇到任何困难,我们的技术支持团队随时为您提供帮助。',
- category: '使用指南'
- },
- {
- id: 2,
- question: '产品有哪些保修政策?',
- answer: '我们为所有产品提供1年的标准保修服务,覆盖制造缺陷和材料问题。部分高端产品可享受最长3年的延长保修服务。保修期内,我们提供免费维修或更换服务。请注意,人为损坏、不当使用或自行拆卸不在保修范围内。\n\n要享受保修服务,您需要提供有效的购买凭证和产品序列号。我们建议您在购买后立即注册产品,以便在需要时更方便地享受保修服务。',
- category: '售后服务'
- },
- {
- id: 3,
- question: '如何进行退换货?',
- answer: '购买后30天内,如产品未使用且包装完好,可申请无理由退换货。请保留原始包装和购买凭证,联系我们的客服团队安排退换事宜。退款将在收到退回产品并确认状态后的7个工作日内处理。\n\n对于有质量问题的产品,我们接受30天内的退换货申请。请提供产品问题的详细描述和照片证明,我们的客服团队会协助您完成退换货流程。',
- category: '售后服务'
- },
- {
- id: 4,
- question: '产品支持哪些操作系统?',
- answer: '我们的软件产品兼容Windows 10/11、macOS 10.15及以上版本、iOS 14及以上版本和Android 10及以上版本。硬件产品与大多数现代设备兼容,具体请查看产品详情页的技术规格部分。\n\n我们定期更新软件以确保与最新操作系统兼容。如果您使用的是较旧版本的操作系统,可能会遇到兼容性问题。我们建议您将操作系统更新到最新版本以获得最佳体验。',
- category: '技术支持'
- },
- {
- id: 5,
- question: '如何联系客服?',
- answer: '您可以通过多种方式联系我们的客服团队:拨打服务热线400-123-4567(工作日9:00-18:00);发送邮件至support@example.com(24小时内回复);在官网使用在线客服(工作日9:00-20:00);或填写联系表单,我们会尽快与您联系。\n\n对于紧急问题,我们建议您优先使用电话或在线客服渠道,以获得更快的响应。非工作时间提交的问题将在下一个工作日处理。',
- category: '联系方式'
- },
- {
- id: 6,
- question: '是否提供国际配送服务?',
- answer: '是的,我们提供国际配送服务,覆盖大部分国家和地区。国际订单的配送时间通常为7-15个工作日,具体取决于目的地和当地海关情况。国际订单可能产生额外的关税和进口费用,这些费用需由收件人承担。\n\n对于大批量的国际订单,我们提供特别的物流解决方案,请联系我们的销售团队了解详情。在特殊情况下(如假期、天气恶劣或当地政策限制),配送时间可能会延长。',
- category: '配送信息'
- },
- {
- id: 7,
- question: '如何跟踪我的订单?',
- answer: '下单后,您将收到一封包含订单确认和跟踪信息的电子邮件。您可以使用提供的跟踪号在我们的网站上或通过物流公司的网站查询订单状态。您也可以登录您的账户查看订单历史和当前状态。如果您有任何疑问,请联系我们的客服团队。',
- category: '配送信息'
- },
- {
- id: 8,
- question: '产品可以升级吗?',
- answer: '是的,我们的大部分产品支持软件升级,我们会定期发布更新以提供新功能和修复已知问题。对于硬件产品,部分型号支持组件升级,请参考产品说明书或联系技术支持了解详情。我们建议您定期检查更新,以保持产品处于最佳状态。',
- category: '技术支持'
- },
- {
- id: 9,
- question: '如何获取使用指南?',
- answer: '所有产品的电子版使用指南可在我们的官网下载中心获取。您也可以在产品包装内找到纸质版使用说明书。对于特定产品的详细教程和技巧,请访问我们的知识库或YouTube频道。如果您需要其他语言版本的使用指南,请联系客服。',
- category: '使用指南'
- }
- ];
-
- // 保存所有FAQ以便于获取相关问题
- allFaqs.value = mockFaqs;
-
- const foundFaq = mockFaqs.find(item => item.id === faqId.value);
-
- if (foundFaq) {
- faq.value = foundFaq;
- } else {
- error.value = new Error('未找到该问题');
- }
-
- return faq.value;
- });
- }
-
- // 页面加载时获取FAQ详情
- onMounted(() => {
- loadFaqDetail();
- });
-
- // SEO优化
- useHead({
- title: computed(() => faq.value ? `${faq.value.question} - FAQ - Hanye` : 'FAQ详情 - Hanye'),
- meta: [
- {
- name: 'description',
- content: computed(() => faq.value?.answer?.substring(0, 150) + '...' || '查看详细的FAQ回答和相关问题。')
- }
- ]
- });
- </script>
-
- <style>
- .prose p {
- margin-top: 1.25em;
- margin-bottom: 1.25em;
- }
- </style>
|